/* Orbas:
 *     A open source CORBA Specification implementation from Huihoo.
 *
 * Copyright 2002-2003 Huihoo.org, Inc. All Right Reserved.
 *
 * This software is licensed under LGPL license.
 * See terms of license at gnu.org.
 *
 * For more information, visit:
 *
 * http://www.huihoo.org/orbas
 */

package org.huihoo.orbas.idl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;

public class GlobalInputStream {

	private static InputStream stream;
	private static Stack lookahead_stack;
	private static boolean included;
	private static StringBuffer expandedText;
	private static int pos;
	private static boolean eof;
	private static File currentFile;
	private static String[] path_names;

	/** stack of information for lexical scopes */
	static java.util.Stack positions;

	public static void init() {
		lookahead_stack = new Stack();
		included = false;
		expandedText = new StringBuffer();
		pos = 0;
		eof = false;
		currentFile = null;
		positions = new java.util.Stack();
	}

	public static void setInput(String fname) throws java.io.IOException {
		currentFile = new File(fname);
		stream = new java.io.FileInputStream(currentFile);
	}

	public static boolean includeState() {
		return included;
	}

	public static void insert(String str) {
		expandedText.insert(pos, str);
	}

	public static void include(String fname, char lookahead,
			boolean useIncludePath) throws FileNotFoundException {
		// System.out.println( "Including " + fname + " , lookahead char is " +
		// (char)lookahead );
		included = true;
		PositionInfo position = lexer.getPosition();
		position.file = currentFile();
		position.stream = stream;

		stream = find(fname, useIncludePath);

		positions.push(position);
		lookahead_stack.push(new Character(lookahead));

		Environment.output(2, "Including " + fname);
		/* files form their own scopes, so we have to open a new one here */
	}

	public static void setIncludePath(String path) {
		java.util.StringTokenizer strtok = new java.util.StringTokenizer(path,
				File.pathSeparator);

		int i;
		if (path_names == null) {
			path_names = new String[strtok.countTokens()];
			i = 0;
		} else {
			i = path_names.length;

			String[] _path_names = new String[strtok.countTokens()
					+ path_names.length];
			for (int j = 0; j < path_names.length; j++)
				_path_names[j] = path_names[j];
			path_names = _path_names;
		}

		while (strtok.hasMoreTokens()) {
			path_names[i++] = strtok.nextToken();
		}
	}

	/**
	 * tries to locate and open a new file for "fname", updates currentFile if
	 * successful
	 */

	private static FileInputStream find(String fname, boolean useIncludePath)
			throws FileNotFoundException {
		if (!useIncludePath) {
			if (fname.indexOf(File.separator) != 0) {
				String dir = null;
				try {
					dir = currentFile.getCanonicalPath();
					if (dir.indexOf(File.separator) > -1) {
						dir = dir.substring(0, dir.lastIndexOf(File.separator));
					}
				} catch (java.io.IOException ioe) {
					// should not happen
					ioe.printStackTrace();
				}

				Environment
						.output(3, "opening " + dir + File.separator + fname);
				currentFile = new File(dir + File.separator + fname);
			} else
				currentFile = new File(fname);

			try {
				return new FileInputStream(currentFile);
			} catch (java.io.IOException iof) {
				return find(fname, true);
			}
		} else {
			if (path_names == null) {
				org.huihoo.orbas.idl.parser.fatal_error("File " + fname
						+ " not found in include path", null);
			} else {
				for (int i = 0; i < path_names.length; i++) {
					try {
						Environment.output(3, "opening " + path_names[i]
								+ File.separator + fname);
						currentFile = new File(path_names[i] + File.separator
								+ fname);
						return new FileInputStream(currentFile);
					} catch (FileNotFoundException fnfex) {
					}
				}
			}

			org.huihoo.orbas.idl.parser.fatal_error("File " + fname
					+ " not found in include path", null);
			return null;
		}
	}

	public static File currentFile() {
		return currentFile;
	}

	public static InputStream currentStream() {
		return stream;
	}

	public static int read() throws IOException {
		int ch = 0;

		if (eof) {
			return -1;
		}

		if (expandedText.length() > 0) {
			if (pos < expandedText.length())
				ch = (int) expandedText.charAt(pos++);
			if (pos == expandedText.length()) {
				expandedText = new StringBuffer();
				pos = 0;
			}
		} else {
			ch = stream.read();

			/*
			 * if eof is reached, see whether we were reading from the main
			 * input stream or from an include file. If the latter, switch back
			 * to the main stream
			 */

			if (ch == -1) {
				if (included) {
					stream.close();

					// undo effects of inhibition pragma
					parser.setInhibitionState(false);

					// return to last position in previous file
					PositionInfo positionInfo = (PositionInfo) positions.pop();
					stream = positionInfo.stream;
					currentFile = positionInfo.file;
					ch = ((Character) lookahead_stack.pop()).charValue();

					// ch = stream.read();
					included = !(positions.empty());
					Environment.output(3, "returning to " + currentFile
							+ " included: " + included);
					lexer.restorePosition(positionInfo);
				} else {
					eof = true;
				}
			}
		}
		return ch;
	}

}
